package com.yunhe.option.service.data.impl;

import com.yunhe.option.domain.base.Area;
import com.yunhe.option.domain.data.CostPrice;
import com.yunhe.option.domain.data.SeasonPrice;
import com.yunhe.common.exception.ArgumentErrorException;
import com.yunhe.common.exception.ObjectNotFoundException;
import com.yunhe.common.exception.UniqueConstraintsException;
import com.yunhe.common.model.PageParam;
import com.yunhe.option.repository.data.CostPriceRepository;
import com.yunhe.option.repository.data.impl.CostPriceDao;
import com.yunhe.option.service.base.AreaService;
import com.yunhe.option.service.data.CostPriceService;
import com.yunhe.option.service.data.SeasonPriceService;
import com.yunhe.common.util.QueryUtil;
import com.yunhe.common.util.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 用电电价服务类实现
 * @author liuronglei
 */
@Service
public class CostPriceServiceImpl implements CostPriceService {
    @Autowired
    private CostPriceRepository costPriceRepository;
    @Autowired
    private SeasonPriceService seasonPriceService;
    @Autowired
    private AreaService areaService;
    @Autowired
    private CostPriceDao costPriceDao;

    private void processBeforeSave(CostPrice costPrice)
            throws ArgumentErrorException, UniqueConstraintsException, ObjectNotFoundException{
        if (costPrice.getTitle() == null
                || costPrice.getAreaList() == null
                || costPrice.getProperty() == null
                || costPrice.getSeasonPrice() == null) {
            throw new ArgumentErrorException("参数不能为空");
        }
        String name = costPrice.getName();
        if (StringUtil.isEmpty(name)) {
            throw new ArgumentErrorException("电价标题不能为空");
        }
        String property = costPrice.getProperty();
        if (property == null) {
            throw new ArgumentErrorException("用电性质不能为空");
        }
        List<Long> voltageLevelCodes = costPrice.getVoltageLevelCodes();
        if (voltageLevelCodes.isEmpty()) {
            throw new ArgumentErrorException("电压等级不能为空");
        }
        List<SeasonPrice> prices = costPrice.getSeasonPrice();
        if (prices == null) {
            throw new ArgumentErrorException("季节电价不能为空");
        }
        //判断是否有重复标题的用电电价
        CostPrice costPriceByTitle = costPriceRepository.findByTitle(costPrice.getTitle());
        if (costPriceByTitle != null) {
            if (costPrice.getId() == null|| costPriceByTitle.getId().longValue() != costPrice.getId().longValue()) {
                throw new UniqueConstraintsException("该电价表标题已存在");
            }
        }
        //判断同一用电电价下的季节电价月份是否存在交集
        if (prices != null) {
            int len = 0;
            Set<String> set = new HashSet<>();
            for (SeasonPrice s : prices) {
                if (s.getRunMonth() != null) {
                    String month = s.getRunMonth();
                    String[] split = month.split(",");
                    len += split.length;
                    set.addAll(Arrays.asList(split));
                }
            }
            if (set.size() != len) {
                throw new ArgumentErrorException("所有季节电价的适用月份不可存在交集");
            }
            if (set.size() != 12) {
                throw new ArgumentErrorException("所有季节电价的适用月份未满12个月");
            }
        }
    }

    /**
     * 新增用电电价对象
     * @param costPrice
     * @return
     * @throws ArgumentErrorException
     * @throws UniqueConstraintsException
     * @throws ObjectNotFoundException
     */
    @Transactional(rollbackFor = Exception.class, transactionManager = "transactionManager")
    @Override
    public CostPrice createCostPrice(CostPrice costPrice)
            throws ArgumentErrorException, UniqueConstraintsException, ObjectNotFoundException {
        costPrice.setId(null);
        processBeforeSave(costPrice);
        CostPrice newCostPrice = costPriceRepository.save(costPrice);
        List<SeasonPrice> seasonPrice = costPrice.getSeasonPrice();
        if (seasonPrice != null) {
            seasonPriceService.create(seasonPrice, newCostPrice.getId());
        }
        this.bindVoltages(newCostPrice);
        List<Long> areaList = costPrice.getAreaList();
        if (areaList != null && areaList.size() > 0) {
            Long areaId = areaList.get(areaList.size() - 1);
//            Area area = areaService.findByAreaId(areaId);
            Area area =  areaService.findById(areaId);
            if (area != null) {
                this.bindArea(newCostPrice, area);
            }
        }
        return newCostPrice;
    }

//    @Transactional(rollbackFor = Exception.class, transactionManager = "transactionManager")
//    @Override
//    public Iterable<CostPrice> createCostPrices(List<CostPrice> list) throws ArgumentErrorException, UniqueConstraintsException, ObjectNotFoundException {
//        for(CostPrice costPrice : list) {
//            costPrice.setId(null);
//            processBeforeSave(costPrice);
//        }
//        return costPriceRepository.saveAll(list);
//    }

    /**
     * 根据ID删除用电电价和所属的季节电价，季节电价详情
     * @param costPriceId
     * @throws ArgumentErrorException
     */
    @Transactional(rollbackFor = Exception.class, transactionManager = "transactionManager")
    @Override
    public void delete(Long costPriceId) throws ArgumentErrorException{
        CostPrice costPrice = costPriceRepository.findById(costPriceId).get();
        if (costPrice != null) {
            try{
                costPriceRepository.deleteCostPrice(costPriceId);
            } catch (Exception e) {
                throw new ArgumentErrorException("删除失败");
            }
        }
    }

    /**
     * 更新用电电价对象（全部字段）
     * @param costPrice
     * @return
     * @throws ArgumentErrorException
     * @throws UniqueConstraintsException
     * @throws ObjectNotFoundException
     */
    @Transactional(rollbackFor = Exception.class, transactionManager = "transactionManager")
    @Override
    public CostPrice updateCostPrice(CostPrice costPrice)
            throws ArgumentErrorException, UniqueConstraintsException, ObjectNotFoundException {
        boolean exists = costPrice.getId() != null && costPriceRepository.existsById(costPrice.getId());
        if (!exists) {
            throw new ObjectNotFoundException("找不到ID为" + costPrice.getId() + "的用电电价");
        }
        processBeforeSave(costPrice);
        return costPriceRepository.save(costPrice);
    }

    /**
     * 更新用电电价对象（指定字段）
     * @param costPriceId
     * @param title
     * @param areaList
     * @param property
     * @param voltageLevelCode
     * @param seasonPrices
     * @return
     * @throws ArgumentErrorException
     * @throws UniqueConstraintsException
     * @throws ObjectNotFoundException
     */
    @Transactional(rollbackFor = Exception.class, transactionManager = "transactionManager")
    @Override
    public CostPrice updateCostPrice(Long costPriceId,
                                     String title,
                                     List<Long> areaList,
                                     String property,
                                     List<Long> voltageLevelCode,
                                     List<SeasonPrice> seasonPrices)
            throws ArgumentErrorException, UniqueConstraintsException, ObjectNotFoundException {
        CostPrice costPrice = costPriceRepository.findById(costPriceId).get();
        if (costPrice == null) {
            throw new ObjectNotFoundException("找不到ID为" + costPrice.getId() + "的用电电价");
        }
        Optional.ofNullable(title).ifPresent(costPrice::setTitle);
        Optional.ofNullable(areaList).ifPresent(costPrice::setAreaList);
        Optional.ofNullable(property).ifPresent(costPrice::setProperty);
        Optional.ofNullable(voltageLevelCode).ifPresent(costPrice::setVoltageLevelCodes);
        Optional.ofNullable(seasonPrices).ifPresent(costPrice::setSeasonPrice);
        processBeforeSave(costPrice);
        return costPriceRepository.save(costPrice);
    }

    /**
     * 根据条件查询用电电价
     * @param queryStr
     * @param stationId
     * @param pageParam
     * @return
     */
    @Override
    public Iterable<CostPrice> search(String queryStr,
                                      Long stationId,
                                      PageParam pageParam) {
        if (stationId != null) {
            return costPriceRepository.findByStationId(stationId);
        } else if (StringUtils.isNotEmpty(queryStr)) {
            int page = 0;
            int size = 0;
            Boolean needPage = false;
            if (QueryUtil.needPaging(pageParam)) {
                needPage = true;
                page = pageParam.getPage();
                size = pageParam.getSize();
            }
            if (page > 1) {
                page = page - 1;
            }
            List<String> sortList = pageParam.getSort();
            Iterable<CostPrice> costPrices = costPriceDao.getByQueryStr(queryStr, page, size, sortList);
            List<Long> idList = new ArrayList<>();
            for(CostPrice cp : costPrices) {
                idList.add(cp.getId());
            }
            costPrices = costPriceDao.getInfo(idList);
            List<CostPrice> results = (List<CostPrice>)costPrices;
            if (needPage) {
                Long totalCount = findTotalCount(queryStr);
                Pageable pageable = QueryUtil.getPageRequest(pageParam);
                return new PageImpl<>(results, pageable, totalCount);
            } else {
                return results;
            }
        }
        return null;
    }

    /**
     * 根据ID查找用电电价
     * @param id
     * @return
     */
    @Override
    public Optional<CostPrice> findById(Long id) {
        return costPriceRepository.findById(id);
    }

    /**
     * 返回符合条件的用电电价的总数
     * @param queryStr
     * @return
     */
    @Transactional
    @Override
    public Long findTotalCount(String queryStr) {
        String cypher = "match(cp:CostPrice)-[:AREA_OF]->(a:Area), p=(m)-[r:HAS_CHILD*..2]->(a) where 1=1";
        if (StringUtils.isNotEmpty(queryStr)) {
            cypher ="where cp.title contains {queryStr} or cp.property contains {queryStr} or "
                    + "cp.province contains {queryStr} or cp.city contains {queryStr} or cp.district contains {queryStr}"
                    + " or v.title contains {queryStr} or d.title contains {queryStr} or n.title contains {queryStr} with s";
        }
        cypher = cypher + "return count(g) as count";
        List<Map<String, Object>> list = costPriceDao.search(cypher);
        if (list.size() > 0) {
            return (long)(int)list.get(0).get("count");
        } else {
            return 0L;
        }
    }

    /**
     * 绑定电压等级
     * @param costPrice
     */
    @Transactional
    @Override
    public void bindVoltages(CostPrice costPrice) {
        List<Long> list = costPrice.getVoltageLevelCodes();
        if (list != null) {
            costPriceRepository.bindVoltageLevel(costPrice.getId(), list);
        }
    }

    /**
     * 绑定地区
     * @param costPrice
     * @param area
     */
    @Transactional
    @Override
    public void bindArea(CostPrice costPrice, Area area) {
//        if (costPrice.getProvince() != null && costPrice.getCity() != null && costPrice.getDistrict() != null) {
//            costPriceRepository.bindArea(costPrice.getId(), costPrice.getDistrict().getId());
//        } else if (costPrice.getProvince() != null && costPrice.getCity() != null) {
//            costPriceRepository.bindArea(costPrice.getId(), costPrice.getCity().getId());
//        } else {
//            costPriceRepository.bindArea(costPrice.getId(), costPrice.getProvince().getId());
//        }
        costPriceRepository.bindArea(costPrice.getId(), area.getId());
    }

    /**
     * 绑定电站
     * @param stationId
     * @param costPriceId
     */
    @Transactional
    @Override
    public void bindStation(Long stationId, Long costPriceId) {
        costPriceRepository.bindStation(stationId, costPriceId);
    }
}
